package org.example;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.Data;
import org.example.utils.StrExtractor;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;

public class LogParserApp extends JFrame {
    private static final String DEFAULT_SQL_QUERY = "SELECT * FROM log_info order by LOG_TIME ASC";
    
    private RSyntaxTextArea sqlTextArea;
    private JTable resultTable;
    private DefaultTableModel tableModel;
    private JTextField logFilePathField;
    private JButton browseButton;
    private JProgressBar progressBar; // 添加进度条组件
    private TableRowSorter<DefaultTableModel> sorter; // 添加表格排序器
    
    // Excel各列配置
    private static Map<String, ColumnConfig> columnConfigMap = new HashMap<>();
    
    // Excel表头映射关系
    private static Map<String, String> headerMap = new HashMap<>();

    public LogParserApp() {
        // 从配置文件加载Excel列宽设置
        loadConfig();
        
        initializeComponents();
        setupLayout();
        setupEventHandlers();

        // 初始化数据库
        try {
            DatabaseManager.initializeDatabase();
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(this, "数据库初始化失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    private void loadConfig() {
        try (InputStream input = getClass().getClassLoader().getResourceAsStream("application.properties")) {
            Properties prop = new Properties();
            prop.load(input);
            
            // 加载Excel各列配置
            for (String key : prop.stringPropertyNames()) {
                if (key.startsWith("excel.column.")) {
                    String columnName = key.substring("excel.column.".length());
                    String[] parts = prop.getProperty(key).split(",");
                    if (parts.length == 2) {
                        String header = parts[0];
                        int width = Integer.parseInt(parts[1]);
                        columnConfigMap.put(columnName, new ColumnConfig(header, width));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 使用默认配置
            initDefaultColumnConfig();
        }
        
        // 加载Excel表头映射关系
        try (InputStream input = getClass().getClassLoader().getResourceAsStream("excel-header.properties")) {
            Properties prop = new Properties();
            prop.load(input);
            
            for (String key : prop.stringPropertyNames()) {
                headerMap.put(key, prop.getProperty(key));
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 默认映射关系
            initDefaultHeaderMap();
        }
    }
    
    private void initDefaultColumnConfig() {
        columnConfigMap.put("query", new ColumnConfig("查询内容", 20));
        columnConfigMap.put("log_id", new ColumnConfig("日志ID", 25));
        columnConfigMap.put("user_id", new ColumnConfig("用户ID", 15));
        columnConfigMap.put("message_id", new ColumnConfig("消息ID", 15));
        columnConfigMap.put("domain_id", new ColumnConfig("业务域ID", 15));
        columnConfigMap.put("subject_id", new ColumnConfig("主题ID", 15));
        columnConfigMap.put("processor", new ColumnConfig("处理器", 25));
        columnConfigMap.put("request", new ColumnConfig("请求内容", 50));
        columnConfigMap.put("response", new ColumnConfig("响应内容", 50));
        columnConfigMap.put("elapsed_time", new ColumnConfig("耗时(毫秒)", 15));
        columnConfigMap.put("log_time", new ColumnConfig("日志时间", 20));
    }
    
    private void initDefaultHeaderMap() {
        headerMap.put("query", "查询内容");
        headerMap.put("logId", "日志ID");
        headerMap.put("userId", "用户ID");
        headerMap.put("messageId", "消息ID");
        headerMap.put("domainId", "业务域ID");
        headerMap.put("subjectId", "主题ID");
        headerMap.put("processor", "处理器");
        headerMap.put("request", "请求内容");
        headerMap.put("response", "响应内容");
        headerMap.put("elapsed_time", "耗时(毫秒)");
        headerMap.put("log_time", "日志时间");
    }

    private void initializeComponents() {
        setTitle("日志解析器");
        setSize(1000, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        
        // 从配置文件加载默认日志文件路径和SQL查询语句
        String defaultLogPath = "";
        String defaultSqlQuery = DEFAULT_SQL_QUERY;

        try (InputStream input = getClass().getClassLoader().getResourceAsStream("application.properties")) {
            Properties prop = new Properties();
            prop.load(input);
            defaultLogPath = prop.getProperty("log.file.path", defaultLogPath);
            defaultSqlQuery = prop.getProperty("default.sql.query", defaultSqlQuery);
        } catch (Exception e) {
            e.printStackTrace();
        }

        logFilePathField = new JTextField(30);
        logFilePathField.setText(defaultLogPath);
        browseButton = new JButton("浏览...");

        sqlTextArea = new RSyntaxTextArea(5, 50);
        sqlTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);
        sqlTextArea.setCodeFoldingEnabled(true);
        sqlTextArea.setText(defaultSqlQuery);

        tableModel = new DefaultTableModel();
        resultTable = new JTable(tableModel);
        resultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        
        // 初始化表格排序器
        sorter = new TableRowSorter<>(tableModel);
        resultTable.setRowSorter(sorter);
        
        // 启用表格单元格内的换行符显示
        resultTable.setDefaultRenderer(Object.class, new javax.swing.table.DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                if (c instanceof JLabel && value instanceof String) {
                    String text = (String) value;
                    // 将\n替换为HTML换行标签以在表格中正确显示
                    if (text.contains("\n")) {
                        JLabel label = (JLabel) c;
                        label.setText("<html>" + text.replace("\n", "<br>") + "</html>");
                    }
                }
                return c;
            }
        });

        // 初始化进度条
        progressBar = new JProgressBar();
        progressBar.setIndeterminate(false);
        progressBar.setVisible(false);
    }

    private void setupLayout() {
        // 输入面板
        JPanel inputPanel = new JPanel(new GridBagLayout());
        inputPanel.setBorder(BorderFactory.createTitledBorder("日志解析参数"));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;

        // 日志文件路径
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        inputPanel.add(new JLabel("日志文件:"), gbc);
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        inputPanel.add(logFilePathField, gbc);
        gbc.gridx = 2;
        gbc.gridy = 2;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.NONE;
        gbc.weightx = 0;
        inputPanel.add(browseButton, gbc);

        // 解析按钮
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.gridwidth = 3;
        JButton parseButton = new JButton("解析并存储日志");
        inputPanel.add(parseButton, gbc);

        // 添加进度条到界面
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(progressBar, gbc);

        // SQL查询面板
        JPanel sqlPanel = new JPanel(new BorderLayout());
        sqlPanel.setBorder(BorderFactory.createTitledBorder("SQL查询"));
        // 使用RTextScrollPane替换JScrollPane以支持RSyntaxTextArea的功能
        sqlPanel.add(new RTextScrollPane(sqlTextArea), BorderLayout.CENTER);

        JButton executeButton = new JButton("执行SQL");
        JButton formatButton = new JButton("格式化SQL"); // 添加格式化按钮
        formatButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                formatSQL();
            }
        });
        
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.add(formatButton); // 添加格式化按钮到面板
        buttonPanel.add(executeButton);
        sqlPanel.add(buttonPanel, BorderLayout.SOUTH);

        // 结果面板
        JPanel resultPanel = new JPanel(new BorderLayout());
        resultPanel.setBorder(BorderFactory.createTitledBorder("查询结果"));

        // 添加导出按钮
        JButton exportButton = new JButton("导出到Excel");
        exportButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                exportTableToExcel();
            }
        });

        JPanel resultButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        resultButtonPanel.add(exportButton);
        resultPanel.add(resultButtonPanel, BorderLayout.NORTH);
        resultPanel.add(new JScrollPane(resultTable), BorderLayout.CENTER);

        // 主面板，使用JSplitPane实现可调整大小的面板
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitPane.setTopComponent(sqlPanel);
        splitPane.setBottomComponent(resultPanel);
        splitPane.setDividerLocation(200); // 设置初始分割位置
        splitPane.setResizeWeight(0.5); // 设置调整大小时上下面板的权重

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(inputPanel, BorderLayout.NORTH);
        mainPanel.add(splitPane, BorderLayout.CENTER);

        add(mainPanel);

        // 为解析按钮添加事件监听器
        parseButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                parseAndStoreAllLogs();
            }
        });

        // 为浏览按钮添加事件监听器
        browseButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                browseLogFile();
            }
        });

        // 为执行SQL按钮添加事件监听器
        executeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                executeSQL();
            }
        });
    }

    private void setupEventHandlers() {
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    private void browseLogFile() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setCurrentDirectory(new File("."));
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChooser.setMultiSelectionEnabled(false);

        // 设置文件过滤器，只显示.log文件
        fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
            @Override
            public boolean accept(File f) {
                return f.getName().toLowerCase().endsWith(".log") || f.isDirectory();
            }

            @Override
            public String getDescription() {
                return "Log Files (*.log)";
            }
        });

        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            logFilePathField.setText(selectedFile.getAbsolutePath());
        }
    }

    private void parseAndStoreAllLogs() {
        // 在新线程中执行耗时操作，避免阻塞UI线程
        new Thread(() -> {
            // 显示进度条
            SwingUtilities.invokeLater(() -> {
                progressBar.setVisible(true);
                progressBar.setIndeterminate(true);
                setInteractionEnabled(false);
            });

            try {
                Map<String, Integer> processorOrder = new LinkedHashMap<>();
                int index = 0;
                for (String key : LogExtractor.processorMap.keySet()) {
                    processorOrder.put(key, index++);
                }

                String logFilePath = logFilePathField.getText().trim();

                if (logFilePath.isEmpty()) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this, "请选择日志文件", "提示", JOptionPane.WARNING_MESSAGE);
                    });
                    return;
                }

                File logFile = new File(logFilePath);
                if (!logFile.exists()) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this, "日志文件不存在: " + logFilePath, "错误", JOptionPane.ERROR_MESSAGE);
                    });
                    return;
                }

                // 解析日志
                List<LogExtractor.LogInfo> logInfos = extractAllLogInfo(logFilePath);
                if (logInfos.isEmpty()) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this, "未找到有效的日志数据", "提示", JOptionPane.INFORMATION_MESSAGE);
                    });
                }

                List<LogPO> pos = new ArrayList<>();
                // 每一个messageId 是一个完整的流程
                Map<String, List<LogExtractor.LogInfo>> answerGroupIdMap = logInfos.stream()
                        .collect(Collectors.groupingBy(LogExtractor.LogInfo::getMessageId));

                Map<String, String> queryMap = new HashMap<>();

                answerGroupIdMap.forEach((msgId, msgLogs) -> {
                    // 对日志按处理器顺序排序
                    List<LogExtractor.LogInfo> orderList = msgLogs.stream()
                            .sorted(Comparator.comparingInt(logInfo -> {
                                String currentProcessor = logInfo.getCurrentProcessor();
                                // 获取currentProcessor在processorMap中的索引顺序
                                return processorOrder.getOrDefault(currentProcessor, Integer.MAX_VALUE);
                            }))
                            .collect(Collectors.toList());

                    // 创建一个Map来存储不同处理器的日志信息
                    Map<String, LogPO> processorLogMap = new HashMap<>();

                    // 处理排序后的日志信息
                    for (LogExtractor.LogInfo logInfo : orderList) {
                        String currentProcessor = logInfo.getCurrentProcessor();
                        
                        // 如果该处理器还没有对应的LogPO对象，则创建一个新的
                        if (!processorLogMap.containsKey(currentProcessor)) {
                            LogPO logPO = new LogPO();
                            logPO.setMessageId(msgId);
                            logPO.setLogId(logInfo.getLogId());
                            logPO.setUserId(logInfo.getUserId());
                            logPO.setDomainId(logInfo.getDomainId());
                            logPO.setSubjectId(logInfo.getSubjectId());
                            String processorName = LogExtractor.processorMap.get(currentProcessor);
                            logPO.setProcessor(currentProcessor + "【" + processorName + "】");
                            logPO.setLog_time(timestampToStr(logInfo.getLogTime()));
                            
                            // 如果是UnderstandProcessor且是请求类型，提取查询内容
                            if ("UnderstandProcessor".equals(currentProcessor) && "request".equals(logInfo.getBusinessType())) {
                                logPO.setQuery(StrExtractor.extractQueryValue(logInfo.getRequestBody()));
                                queryMap.put(msgId, logPO.getQuery());
                            }
                            
                            processorLogMap.put(currentProcessor, logPO);
                        }
                        
                        // 获取对应的LogPO对象
                        LogPO logPO = processorLogMap.get(currentProcessor);
                        
                        // 根据业务类型设置请求或响应内容
                        if ("request".equals(logInfo.getBusinessType())) {
                            String requestBody = logInfo.getRequestBody();
                            // 使用processJsonValue方法确保正确处理编码
                            if (requestBody != null) {
                                requestBody = processJsonValue(requestBody);
                            }
                            logPO.setRequest(requestBody);
                        } else if ("response".equals(logInfo.getBusinessType())) {
                            String outputData = logInfo.getOutputData();
                            // 使用processJsonValue方法确保正确处理编码
                            if (outputData != null) {
                                outputData = processJsonValue(outputData);
                            }
                            logPO.setResponse(outputData);
                        } else if ("time".equals(logInfo.getBusinessType())) {
                            logPO.setElapsed_time(logInfo.getRt());
                        }
                    }
                    
                    // 将处理好的LogPO对象添加到结果列表中
                    pos.addAll(processorLogMap.values());
                });


                for (LogPO po : pos) {
                    po.setQuery(queryMap.get(po.getMessageId()));
                }

                // 存储到数据库（使用批量插入）
                final int total = pos.size();

                // 更新进度条为确定模式
                SwingUtilities.invokeLater(() -> {
                    progressBar.setIndeterminate(false);
                    progressBar.setMaximum(total);
                    progressBar.setValue(0);
                });

                // 分批插入数据，每批1000条
                int batchSize = 1000;
                for (int i = 0; i < pos.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, pos.size());
                    List<LogPO> batch = pos.subList(i, endIndex);
                    DatabaseManager.batchInsertLogInfo(batch);

                    // 更新进度条
                    final int current = endIndex;
                    SwingUtilities.invokeLater(() -> {
                        progressBar.setValue(current);
                        progressBar.setString("正在存储日志: " + current + "/" + total);
                        progressBar.setStringPainted(true);
                    });
                }

                final int finalCount = pos.size();
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this, "成功解析并存储 " + finalCount + " 条日志记录", "成功", JOptionPane.INFORMATION_MESSAGE);
                    // 自动执行查询语句
                    sqlTextArea.setText(DEFAULT_SQL_QUERY);
                    executeSQL();
                });

            } catch (IOException e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this, "读取日志文件失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                });
            } catch (SQLException e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this, "存储日志到数据库失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                });
            } catch (Exception e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this, "处理日志时发生错误: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                });
            } finally {
                // 隐藏进度条并恢复界面交互
                SwingUtilities.invokeLater(() -> {
                    progressBar.setVisible(false);
                    progressBar.setStringPainted(false);
                    setInteractionEnabled(true);
                });
            }
        }).start();
    }

    // 设置界面组件的可交互状态
    private void setInteractionEnabled(boolean enabled) {
        // 获取父容器中的所有组件
        Component[] components = getContentPane().getComponents();
        setComponentsEnabled(components, enabled);
    }

    // 递归设置组件及其子组件的启用状态
    private void setComponentsEnabled(Component[] components, boolean enabled) {
        for (Component component : components) {
            if (component instanceof JButton) {
                // 进度条显示时禁用所有按钮
                component.setEnabled(enabled);
            } else if (component instanceof JTextField) {
                component.setEnabled(enabled);
            } else if (component instanceof JTextArea) {
                component.setEnabled(enabled);
            } else if (component instanceof Container) {
                // 递归处理容器内的组件
                setComponentsEnabled(((Container) component).getComponents(), enabled);
            }
        }
    }

    // 解析所有日志记录的方法
    private List<LogExtractor.LogInfo> extractAllLogInfo(String filePath) throws IOException {
        return LogExtractor.extractAllLogInfo(filePath);
    }

    // 导出表格数据到Excel文件
    private void exportTableToExcel() {
        try {
            // 检查是否有数据
            if (tableModel.getRowCount() == 0) {
                JOptionPane.showMessageDialog(this, "没有数据可以导出", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }

            // 定义所有表头
            List<String> allHeaders = new ArrayList<>();
            for (int i = 0; i < tableModel.getColumnCount(); i++) {
                allHeaders.add(tableModel.getColumnName(i));
            }

            // 创建复选框列表
            JCheckBox[] checkBoxes = new JCheckBox[allHeaders.size()];
            JPanel checkboxPanel = new JPanel(new GridLayout(0, 1));
            for (int i = 0; i < allHeaders.size(); i++) {
                checkBoxes[i] = new JCheckBox(allHeaders.get(i), true);
                checkboxPanel.add(checkBoxes[i]);
            }
            
            // 显示列选择对话框
            int result = JOptionPane.showConfirmDialog(this, checkboxPanel, "选择要导出的列", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
            if (result != JOptionPane.OK_OPTION) {
                return;
            }
            
            // 收集选中的列索引和表头
            List<Integer> selectedColumnIndices = new ArrayList<>();
            List<String> selectedHeaders = new ArrayList<>();
            for (int i = 0; i < checkBoxes.length; i++) {
                if (checkBoxes[i].isSelected()) {
                    selectedColumnIndices.add(i);
                    // 从"中文名（字段名）"格式中提取中文名
                    String selected = allHeaders.get(i);
                    String chineseHeader = selected;
                    int endIndex = selected.indexOf("（");
                    if (endIndex > 0) {
                        chineseHeader = selected.substring(0, endIndex);
                    }
                    selectedHeaders.add(chineseHeader);
                }
            }
            
            if (selectedHeaders.isEmpty()) {
                JOptionPane.showMessageDialog(this, "至少需要选择一列进行导出", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }

            // 创建文件选择器
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setDialogTitle("保存Excel文件");
            fileChooser.setSelectedFile(new File("查询结果.xlsx"));

            // 设置文件过滤器
            fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
                @Override
                public boolean accept(File f) {
                    return f.getName().toLowerCase().endsWith(".xlsx") || f.isDirectory();
                }

                @Override
                public String getDescription() {
                    return "Excel文件 (*.xlsx)";
                }
            });

            int userSelection = fileChooser.showSaveDialog(this);

            if (userSelection == JFileChooser.APPROVE_OPTION) {
                File fileToSave = fileChooser.getSelectedFile();
                String filePath = fileToSave.getAbsolutePath();

                // 确保文件有正确的扩展名
                if (!filePath.endsWith(".xlsx")) {
                    filePath += ".xlsx";
                    fileToSave = new File(filePath);
                }

                // 使用hutool创建Excel文件
                ExcelWriter writer = ExcelUtil.getWriter(fileToSave);
                
                // 设置数据居左显示
                writer.getStyleSet().setAlign(HorizontalAlignment.LEFT, VerticalAlignment.CENTER);

                // 创建数据行
                List<List<Object>> rows = new ArrayList<>();
                int rowCount = tableModel.getRowCount();
                for (int row = 0; row < rowCount; row++) {
                    List<Object> rowData = new ArrayList<>();
                    for (int colIndex : selectedColumnIndices) {
                        Object value = tableModel.getValueAt(row, colIndex);
                        // 处理request和response字段中的换行符
                        if (value instanceof String) {
                            String columnHeader = tableModel.getColumnName(colIndex);
                            // 从"中文名（字段名）"格式中提取字段名
                            String fieldName = extractFieldNameFromHeader(columnHeader);
                            if ("request".equals(fieldName) || "response".equals(fieldName)) {
                                // 将字符串中的\n替换为真正的换行符
                                value = ((String) value).replace("\\n", "\n");
                            }
                        }
                        rowData.add(value);
                    }
                    rows.add(rowData);
                }

                // 写入数据
                writer.writeHeadRow(selectedHeaders);
                writer.write(rows);
                
                // 设置单元格样式以支持换行
                for (int i = 0; i < selectedHeaders.size(); i++) {
                    String header = selectedHeaders.get(i);
                    String fieldName = "";
                    // 从中文名查找字段名
                    for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                        if (entry.getValue().equals(header)) {
                            fieldName = entry.getKey();
                            break;
                        }
                    }
                    
                    // 对于request和response列，设置单元格支持换行
                    if ("request".equals(fieldName) || "response".equals(fieldName)) {
                        org.apache.poi.ss.usermodel.CellStyle style = writer.getWorkbook().createCellStyle();
                        style.setWrapText(true);
                        writer.getSheet().setDefaultColumnStyle(i, style);
                    }
                    
                    int columnWidth = 20; // 默认宽度
                    
                    // 根据列名查找对应的配置
                    for (Map.Entry<String, ColumnConfig> entry : columnConfigMap.entrySet()) {
                        if (entry.getValue().getHeader().equals(header)) {
                            columnWidth = entry.getValue().getWidth();
                            break;
                        }
                    }
                    
                    // 设置列宽，但不超过Excel最大限制
                    writer.setColumnWidth(i, Math.min(columnWidth, 255));
                }

                // 关闭writer并写入文件
                writer.close();

                JOptionPane.showMessageDialog(this, "数据已成功导出到: " + filePath, "导出成功", JOptionPane.INFORMATION_MESSAGE);
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, "导出过程中发生错误: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void executeSQL() {
        String sql = sqlTextArea.getText();
        try {
            ResultSet rs = DatabaseManager.executeQuery(sql);
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            // 创建表格模型
            tableModel.setRowCount(0);
            tableModel.setColumnCount(0);

            // 添加列标题（同时显示中文名和字段名）
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnName(i);
                String displayName = headerMap.getOrDefault(columnName.toLowerCase(), columnName);
                // 显示格式为：中文名（字段名）
                String columnTitle = displayName + "（" + columnName + "）";
                tableModel.addColumn(columnTitle);
            }

            // 添加数据行
            while (rs.next()) {
                Object[] row = new Object[columnCount];
                for (int i = 1; i <= columnCount; i++) {
                    Object value = rs.getObject(i);
                    // 处理request和response字段中的换行符
                    if (value instanceof String) {
                        String columnName = metaData.getColumnName(i).toLowerCase();
                        if ("request".equals(columnName) || "response".equals(columnName)) {
                            // 将字符串中的\n替换为真正的换行符
                            value = ((String) value).replace("\\n", "\n");
                        }
                    }
                    row[i - 1] = value;
                }
                tableModel.addRow(row);
            }

            // 设置表格列宽
            setTableColumnWidths();
            
            // 设置特定列的排序规则
            setColumnSortingRules();

            rs.close();
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(this, "SQL执行失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /**
     * 设置特定列的排序规则
     */
    private void setColumnSortingRules() {
        for (int i = 0; i < resultTable.getColumnCount(); i++) {
            String columnName = resultTable.getColumnName(i);
            
            // 为"耗时(毫秒)"列设置数字排序器
            if (columnName.contains("耗时(毫秒)")) {
                sorter.setComparator(i, new Comparator<String>() {
                    @Override
                    public int compare(String s1, String s2) {
                        try {
                            // 尝试按数字排序
                            Integer i1 = s1 != null ? Integer.parseInt(s1) : 0;
                            Integer i2 = s2 != null ? Integer.parseInt(s2) : 0;
                            return i1.compareTo(i2);
                        } catch (NumberFormatException e) {
                            // 如果不是数字，按字符串排序
                            return s1 != null ? s1.compareTo(s2 != null ? s2 : "") : 
                                   s2 != null ? -1 : 0;
                        }
                    }
                });
            }
            
            // 为"日志时间"列设置时间排序器
            else if (columnName.contains("日志时间")) {
                sorter.setComparator(i, new Comparator<String>() {
                    @Override
                    public int compare(String s1, String s2) {
                        // 按字符串排序 (因为日志时间已经是有序格式)
                        return s1 != null ? s1.compareTo(s2 != null ? s2 : "") : 
                               s2 != null ? -1 : 0;
                    }
                });
            }
        }
    }
    
    /**
     * 从"中文名（字段名）"格式的列标题中提取字段名
     * @param header 列标题
     * @return 字段名
     */
    private String extractFieldNameFromHeader(String header) {
        int startIndex = header.indexOf("（");
        int endIndex = header.indexOf("）");
        if (startIndex >= 0 && endIndex > startIndex) {
            return header.substring(startIndex + 1, endIndex);
        }
        return header;
    }
    
    /**
     * 根据配置设置表格列宽
     */
    private void setTableColumnWidths() {
        for (int i = 0; i < resultTable.getColumnCount(); i++) {
            String columnName = resultTable.getColumnName(i);
            // 从"中文名（字段名）"格式中提取中文名
            String displayName = columnName;
            int endIndex = columnName.indexOf("（");
            if (endIndex > 0) {
                displayName = columnName.substring(0, endIndex);
            }
            
            // 查找匹配的列配置
            ColumnConfig config = null;
            for (Map.Entry<String, ColumnConfig> entry : columnConfigMap.entrySet()) {
                if (entry.getValue().getHeader().equals(displayName)) {
                    config = entry.getValue();
                    break;
                }
            }
            
            // 如果找到了配置，则设置列宽
            if (config != null) {
                resultTable.getColumnModel().getColumn(i).setPreferredWidth(config.getWidth() * 10);
            } else {
                // 默认列宽
                resultTable.getColumnModel().getColumn(i).setPreferredWidth(100);
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception e) {
                    e.printStackTrace();
                }

                new LogParserApp().setVisible(true);
            }
        });
    }

    @Data
    public static class LogPO {
        // BaseInfo的属性
        private String query;
        private String logId;
        private String userId;
        private String messageId;
        private String domainId;
        private String subjectId;

        // 原有的LogPO属性
        String processor;
        String request;
        String response;
        String elapsed_time;
        String log_time;
    }

    // 时间戳（毫秒）→ 格式字符串
    public static String timestampToStr(long timestamp) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
                .withZone(ZoneId.systemDefault()); // 指定时区
        return formatter.format(Instant.ofEpochMilli(timestamp));
    }
    
    /**
     * 处理JSON值中的转义字符
     * @param value 原始值
     * @return 处理后的值
     */
    private static String processJsonValue(String value) {
        if (value == null || value.isEmpty()) {
            return value;
        }
        
        // 如果是JSON格式，保留原始格式，只处理必要的编码问题
        if (isJsonString(value)) {
            // 只处理编码问题，不破坏JSON结构
            // 处理Unicode转义序列
            java.util.regex.Pattern unicodePattern = java.util.regex.Pattern.compile("\\\\u([0-9a-fA-F]{4})");
            java.util.regex.Matcher unicodeMatcher = unicodePattern.matcher(value);
            StringBuffer sb = new StringBuffer();
            while (unicodeMatcher.find()) {
                char unicodeChar = (char) Integer.parseInt(unicodeMatcher.group(1), 16);
                unicodeMatcher.appendReplacement(sb, Character.toString(unicodeChar));
            }
            unicodeMatcher.appendTail(sb);
            value = sb.toString();
        } else {
            // 处理常见的转义字符
            value = value.replace("\\\"", "\"");
            value = value.replace("\\n", "\n");
            value = value.replace("\\r", "\r");
            value = value.replace("\\t", "\t");
            value = value.replace("\\\\", "\\");
            
            // 处理Unicode转义序列
            java.util.regex.Pattern unicodePattern = java.util.regex.Pattern.compile("\\\\u([0-9a-fA-F]{4})");
            java.util.regex.Matcher unicodeMatcher = unicodePattern.matcher(value);
            StringBuffer sb = new StringBuffer();
            while (unicodeMatcher.find()) {
                char unicodeChar = (char) Integer.parseInt(unicodeMatcher.group(1), 16);
                unicodeMatcher.appendReplacement(sb, Character.toString(unicodeChar));
            }
            unicodeMatcher.appendTail(sb);
            value = sb.toString();
        }
        
        return value;
    }
    
    /**
     * 判断字符串是否为JSON格式
     * @param str 待判断的字符串
     * @return 是否为JSON格式
     */
    private static boolean isJsonString(String str) {
        if (str == null || str.length() < 2) {
            return false;
        }
        str = str.trim();
        char firstChar = str.charAt(0);
        char lastChar = str.charAt(str.length() - 1);
        return (firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']');
    }
    
    /**
     * 格式化SQL语句
     */
    private void formatSQL() {
        try {
            String sql = sqlTextArea.getText();
            if (sql != null && !sql.trim().isEmpty()) {
                // 使用sql-formatter库格式化SQL
                String formattedSQL = formatSqlWithLibrary(sql);
                sqlTextArea.setText(formattedSQL);
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, "SQL格式化失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /**
     * 使用第三方库格式化SQL
     * @param sql 原始SQL
     * @return 格式化后的SQL
     */
    private String formatSqlWithLibrary(String sql) {
        try {
            // 使用sql-formatter库进行格式化
            // 这里我们使用一个简单的实现
            return formatSqlSimple(sql);
        } catch (Exception e) {
            // 如果格式化失败，返回原始SQL
            return sql;
        }
    }
    
    /**
     * 简单的SQL格式化实现
     * @param sql 原始SQL
     * @return 格式化后的SQL
     */
    private String formatSqlSimple(String sql) {
        // 简单的SQL格式化实现
        StringBuilder formatted = new StringBuilder();
        int indentLevel = 0;
        String[] tokens = sql.replaceAll("([(),;])", " $1 ")
                            .replaceAll("\\s+", " ")
                            .trim()
                            .split("\\s+");
       String[] indentBefore = {"SELECT", "FROM", "WHERE", "AND", "OR", "ORDER", "GROUP", "HAVING", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "ALTER"};
        String[] indentAfter = {"SELECT", "FROM", "WHERE", "SET", "VALUES"};
        
        for (int i = 0; i < tokens.length; i++) {
            String token = tokens[i].toUpperCase();
            
            // 检查是否需要在关键词前增加缩进和换行
            if (isInArray(token, indentBefore) && i > 0) {
                formatted.append("\n");
                if ("WHERE".equals(token) || "AND".equals(token) || "OR".equals(token)) {
                    for (int j = 0; j < indentLevel; j++) formatted.append("  ");
                } else {
                    indentLevel++;
                    for (int j = 0; j < indentLevel - 1; j++) formatted.append("  ");
                }
            }
            
            formatted.append(tokens[i]).append(" ");
            
            // 检查是否需要在关键词后增加缩进
            if (isInArray(token, indentAfter)) {
                formatted.append("\n");
                for (int j = 0; j < indentLevel; j++) formatted.append("  ");
            } else if ("(".equals(token)) {
                indentLevel++;
            } else if (")".equals(token)) {
                indentLevel--;
            }
        }
        
        return formatted.toString().trim();
    }
    
    /**
     * 检查字符串是否在数组中
     * @param str 要检查的字符串
     * @param arr 字符串数组
     * @return 是否存在
     */
    private boolean isInArray(String str, String[] arr) {
        for (String s : arr) {
            if (s.equals(str)) {
                return true;
            }
        }
        return false;
    }
}